﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TemplateMethod
{
    class Program
    {
        static void Main(string[] args)
        {
            //AbstractClass a = new ConcreteClassA();
            //a.PrimitiveOperation1();
            //a.PrimitiveOperation2();
            //Console.WriteLine("call primitive method with a end");
            //a.TemplateMethod();
            //AbstractClass b = new ConcreteClassB();
            //b.PrimitiveOperation1();
            //b.PrimitiveOperation2();
            //Console.WriteLine("call primitive method with b end");
            //b.TemplateMethod();

            DataAccessObject a = new Categories();
            a.TemplateMethod();
            Console.WriteLine();
            DataAccessObject b = new Products();
            b.TemplateMethod();

            Console.Read();
        }
    }

    abstract class AbstractClass
    {
        public abstract void PrimitiveOperation1();
        public abstract void PrimitiveOperation2();

        public void TemplateMethod()
        {
            PrimitiveOperation1();
            PrimitiveOperation2();
            Console.WriteLine();
        }
    }

    class ConcreteClassA : AbstractClass
    {
        public override void PrimitiveOperation1()
        {
            Console.WriteLine("ConcreteClassA.PrimitiveOperation1 method be called");
        }

        public override void PrimitiveOperation2()
        {
            Console.WriteLine("ConcreteClassA.PrimitiveOperation2 method be called");
        }
    }

    class ConcreteClassB : AbstractClass
    {
        public override void PrimitiveOperation1()
        {
            Console.WriteLine("ConcreteClassB.PrimitiveOperation1 method be called");
        }

        public override void PrimitiveOperation2()
        {
            Console.WriteLine("ConcreteClassB.PrimitiveOperation2 method be called");
        }
    }

    abstract class DataAccessObject
    {
        public virtual void Connect()
        {
            Console.WriteLine("database is connected");
        }

        public abstract void Select();
        public abstract void Proccess();

        public virtual void Disconnect()
        {
            Console.WriteLine("database is disconnected");
        }

        public void TemplateMethod()
        {
            Connect();
            Select();
            Proccess();
            Disconnect();
        }
    }

    class Categories : DataAccessObject
    {
        public override void Select()
        {
            Console.WriteLine("{0} is selected", this.GetType().Name);
        }
        public override void Proccess()
        {
            Console.WriteLine("{0} is proccessed", this.GetType().Name);
        }
    }

    class Products : DataAccessObject
    {
        public override void Select()
        {
            Console.WriteLine("{0} is selected", this.GetType().Name);
        }
        public override void Proccess()
        {
            Console.WriteLine("{0} is proccessed", this.GetType().Name);
        }
    }
}
